﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Media.Media3D;

namespace CrazyWorship1
{
    /// <summary>
    /// This class encapsulates a TranslateTransform3D object but
    /// presents a different interface.  Instead of x, y, and z
    /// offsets, we use a unit vector and a scaling factor.
    /// 
    /// This class was created specifically to allow a DoubleAnimation
    /// to use the Distance property as a target.  For that reason,
    /// Distance is a DependencyProperty.
    /// 
    /// Intuitively, this class should derive from DependencyObject,
    /// but when I do this, the code compiles but the animation
    /// doesn't work.  If I instead just change the base class
    /// to UIElement, it works.  I'm not yet sure why.
    /// </summary>
    public class VectorTranslateTransform3D : UIElement
    {
        // This is a unit vector
        private Vector3D _direction;

        // This is the encapsulated transform object.
        private TranslateTransform3D _tt;

        public VectorTranslateTransform3D(
            TranslateTransform3D tt,
            Vector3D dir,
            double dist)
        {
            _tt = tt;
            Direction = dir;
            Distance = dist;
        }

        /// <summary>
        /// When the vector or the distance changes, we need to 
        /// update the encapsulated transform object.
        /// </summary>
        private void update()
        {
            // multiply the unit vector times the distance to get 
            // the full translation
            Vector3D vec = _direction * Distance;

            _tt.OffsetX = vec.X;
            _tt.OffsetY = vec.Y;
            _tt.OffsetZ = vec.Z;
        }

        public Vector3D Direction
        {
            get
            {
                return _direction;
            }
            set
            {
                _direction = value;
                _direction.Normalize();
                update();
            }
        }

        public double Distance
        {
            get
            {
                return (double)this.GetValue(DistanceProperty);
            }
            set
            {
                this.SetValue(DistanceProperty, value);
            }
        }

        private static void DistanceChangedCallback(
            DependencyObject d,
            DependencyPropertyChangedEventArgs e)
        {
            VectorTranslateTransform3D v =
                (VectorTranslateTransform3D)d;

            v.update();
        }

        public static readonly DependencyProperty DistanceProperty =
            DependencyProperty.Register(
                "Distance",
                typeof(double),
                typeof(VectorTranslateTransform3D),
                new PropertyMetadata(
                new PropertyChangedCallback(DistanceChangedCallback)));
    }
}
